package com.itstyle.seckill.topic.jichu;

/**
 * @Auther: liuwenxiang
 * @Date: 2020/3/11 21:53
 * @Description:
 * 泛型--参数化类型的应用:
 *     常见用法：//泛型的概念//泛型类//泛型方法//泛型限制//T与?的区别
 *     T K V E  <T> <T,K>  <T extends 对象>
 *     K 表示键，V 表示值，E 表示异常或错误，T 表示一般意义上的数据类型
 *     extends 表示泛型继承于某个类
 *
 *
 *     1.在泛型中，不但数据的值可以通过参数传递，数据的类型也可以通过参数传递。
 *     T1, T2 只是数据类型的占位符，运行时会被替换为真正的数据类型。
 *
 *     2.传值参数（我们通常所说的参数）由小括号包围，如 (int x, double y)，
 *     类型参数（泛型参数）由尖括号包围，多个参数由逗号分隔，如<T> 或 <T, E>。--<>表示声明泛型 T等是类型参数
 *
      3.泛型类在"实例化"时必须指出具体的类型，也就是向类型参数传值，格式为：
      className variable<dataType1, dataType2> = new className<dataType1, dataType2>();
      也可以省略等号右边的数据类型，但是会产生警告，即：
      className variable<dataType1, dataType2> = new className();

      4.泛型类:  --常用于多个对象的类的"结构相同"，而成员变量的"属性不同"
        public class FXPoint<T1,T2>

        泛型方法:
        一旦定义了类型参数，就可以在参数列表、方法体和返回值类型中使用了
        public static <V1, V2> void printPoint(V1 x, V2 y){
            V1 m = x;
            V2 n = y;
            System.out.println("This point is：" + m + ", " + n);
        }
        ps：泛型方法与泛型类没有必然的联系，泛型类中的泛型用于类中的参数

      5。类型擦除/限制泛型的可用类型/
        定义了泛型，在new对象的时候，可以不用,就像new普通对象一样。
        <T extends 对象>

      6.通配符<?>和类型参数<T>的区别就在于，对编译器来说所有的T都代表同一种类型
        上界<? extends T>不能往里存，只能往外取
        下界<? super T>不影响往里存，但往外取只能放在Object对象里

        "<T>“和”<?>"，首先要区分开两种不同的场景：

        泛型三种：
        [1]ArrayList<T> al=new ArrayList<T>();指定集合元素只能是T类型
        [2]ArrayList<?> al=new ArrayList<?>();集合元素可以是任意类型，这种没有意义，一般是方法中，只是为了说明用法
        [3]ArrayList<? extends E> al=new ArrayList<? extends E>();
        泛型的限定：
        ? extends E:接收E类型或者E的子类型。
        ？super E:接收E类型或者E的父类型。

        第一，声明一个泛型类或泛型方法。
        第二，使用泛型类或泛型方法。
        类型参数“<T>”主要用于第一种，声明泛型类或泛型方法。
        无界通配符“<?>”主要用于第二种，使用泛型类或泛型方法

 * 向上转型  ---
 * int –> Integer –> Object
 * double –>Double –> Object
 * String –> Object
 * 向下转型
 * 自动装箱 int---Intger
 *
 * Object 是所有类的祖先类，任何一个类的实例都可以向上转型为 Object 类型
 * 定义对象的属性为Object，设置的时候可以任意设置，这个过程是向上转型，
 * 但是取值的时候"向下转型"容易发生异常，例如setObject("ee"),取值的时候Integer a =getObject("ee")就会异常。
 *
 *
 * 区别：
 * "类型参数"(泛型)只能用来表示"引用类型"，不能用来表示基本类型，如 int、double、char 等。
 * 但是传递基本类型不会报错，因为它们会自动装箱成对应的包装类。
 */
public class FXPoint<T1,T2> {
    T1 x;
    T2 y;
    public  T1 getX(){
        return x;
    }

    public T2 getY(){
        return y;
    }

    public void setX(T1 x){
        this.x=x;
    }
    public void  setY(T2 y){
        this.y=y;
    }

    // 定义泛型方法
    public <T1 extends Integer, T2 > T1 printPoint(T1 x, T2 y){
        T1 m = x;
        T2 n = y;
        System.out.println("This point is：" + m + ", " + n);
        return x;
    }



    public static void main(String[] args) {
        FXPoint<Integer,Double> point =new FXPoint();
        point.setX(1);
        point.setY(11D);
        point.printPoint(123,3F);

        System.out.println(point);

        System.out.println(Sex.fale.name);
        Student.getName("1",3);

        /**
         * "非静态内部类"和"静态内部类"相当于外部类的非静态特性和静态特性，就像类的属性和方法，
         * 这个就是类的类，一个包含属性和方法的逻辑单元，外部类就像调自己的方法和属性一样去调用它。
         *
         *
         *
         * 非静态内部类
         */
        InnClass.InnnerClass1 innnerClass1 = new InnClass.InnnerClass1();
        InnClass.InnnerClass1.m();
        innnerClass1.n();

        /**
         * 静态内部类
         */
        InnClass.InnnerClass innnerClass = new InnClass().new InnnerClass();
        Student<String,Integer> student = new Student();
    }

    /**
     * 枚举* @param <T2>
     */
   private static class Student<T1,T2>{
         T1 t1;
         T2 t2;

         public static  <K extends String,V> K getName(K k,V v){
             System.out.println(k);
             return null;
         }

    }

    /**
     * 枚举
     */
     enum Sex{

         fale(1,"男"),
         mfale(2,"女");
         private int code;
         private String name;
         Sex(int code,String name){
                this.code=code;
                this.name=name;
         }
         public int getCode(){
             return code;
         }

         public String getName(){
             return name;
         }
         public static String getNameByCode(int code){
             for (Sex sex :values()){
                 if(sex.code==code){
                     return sex.name();
                 }
             }
             return null;
         }
     }




}
